package com.youi.third.ali.pay.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.youi.third.ali.pay.model.AliPayQueryResponse;
import com.youi.third.wechat.util.WechatUtil;
import com.youi.util.JsonUtil;
import com.youi.util.LogUtil;

/**
 * 支付宝支付工具类
 * @author erdong.Chan
 *
 */
public class AlipayUtil {
	
	public static String URL=null;	//支付宝网关（固定）
	public static String APP_ID=null;	//APPID即创建应用后生成
	public static String APP_PRIVATE_KEY=null;//开发者应用私钥，由开发者自己生成
	public static String FORMAT=null;	//参数返回格式，只支持json
	public static String CHARSET=null;	//请求和签名使用的字符编码格式，支持GBK和UTF-8
	public static String ALIPAY_PUBLIC_KEY=null;	//支付宝公钥，由支付宝生成
	public static String SIGN_TYPE=null;		//商户生成签名字符串所使用的签名算法类型，目前支持RSA2和RSA，推荐使用RSA2
	public static String ReturnUrl=null;//回跳地址
	public static String NotifyUrl=null;//支付成功通知地址
	public static String PID=null;//实际收款账号，一般填写商户PID即可
	
	private static String SOURCE="#";//收款方姓名
	private static String QUICK_WAP_PAY="QUICK_WAP_PAY";
	private static String FAST_INSTANT_TRADE_PAY="FAST_INSTANT_TRADE_PAY";
	private static String PAYEE_TYPE="ALIPAY_LOGONID";
	public static AlipayClient alipayClient=null;

	
	/**
	 * 加载配置文件
	 */
	static{
        Properties prop = new Properties();
        InputStream in = WechatUtil.class.getResourceAsStream("/alipay.properties");
		try {
		    prop.load(in);
		    String prfix="alipay.";//前缀
		    URL = prop.getProperty(prfix+"URL").trim();
		    APP_ID = prop.getProperty(prfix+"APP_ID").trim();
		    APP_PRIVATE_KEY = prop.getProperty(prfix+"APP_PRIVATE_KEY").trim();
		    FORMAT = prop.getProperty(prfix+"FORMAT").trim();
		    CHARSET = prop.getProperty(prfix+"CHARSET").trim();
		    ALIPAY_PUBLIC_KEY = prop.getProperty(prfix+"ALIPAY_PUBLIC_KEY").trim();
		    SIGN_TYPE = prop.getProperty(prfix+"SIGN_TYPE").trim();
		    ReturnUrl = prop.getProperty(prfix+"ReturnUrl").trim();
		    NotifyUrl = prop.getProperty(prfix+"NotifyUrl").trim();
		    PID = prop.getProperty(prfix+"PID").trim();
			alipayClient=new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	
	public AlipayUtil(String URL,String APP_ID,String APP_PRIVATE_KEY,String FORMAT,String CHARSET,String ALIPAY_PUBLIC_KEY,String SIGN_TYPE,
			String ReturnUrl,String NotifyUrl,String PID) {
		this.URL=URL;
		this.APP_ID=APP_ID;
		this.APP_PRIVATE_KEY=APP_PRIVATE_KEY;
		this.FORMAT=FORMAT;
		this.CHARSET=CHARSET;
		this.ALIPAY_PUBLIC_KEY=ALIPAY_PUBLIC_KEY;
		this.SIGN_TYPE=SIGN_TYPE;
		this.ReturnUrl=ReturnUrl;
		this.NotifyUrl=NotifyUrl;
		this.PID=PID;
		alipayClient=new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
	}
	
	/**
	 * H5发起支付获取form支付页面
	 * @param out_trade_no	订单号
	 * @param amount		金额
	 * @param subject		支付提示信息
	 * @param payType		支付类型 (1扫码  2wap手机跳转 )
	 * @return
	 * @throws AlipayApiException
	 */
	public static String  h5PayGetFormHtml(String out_trade_no,Double amount,String subject,Integer payType){
	    try {
	    	LogUtil.Info("H5发起支付获取form支付页面");
	    	LogUtil.Info("out_trade_no="+out_trade_no);
	    	LogUtil.Info("amount="+amount);
	    	LogUtil.Info("subject="+subject);
	    	LogUtil.Info("payType="+payType);
	    	LogUtil.Info("开始获取form html");
	    	if(payType==1){
	    		AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
			    alipayRequest.setReturnUrl(ReturnUrl+"?orderNumber="+out_trade_no);
			    alipayRequest.setNotifyUrl(NotifyUrl);//在公共参数中设置回跳和通知地址
			    alipayRequest.setBizContent("{" +
			        "    \"out_trade_no\":\""+out_trade_no+"\"," +  //商户订单号，需要保证不重复
			        "    \"total_amount\":\""+amount+"\"," +	//金额
			        "    \"subject\":\""+subject+"\"," +	//订单标题
			        "    \"seller_id\":\""+AlipayUtil.PID+"\"," +
			        "    \"product_code\":\""+FAST_INSTANT_TRADE_PAY+"\"" +
			        "  }");//填充业务参数
				String form = AlipayUtil.alipayClient.pageExecute(alipayRequest).getBody();
				LogUtil.Info("发起支付获取扫码 form html成功");
				return form;
	    	}else {
	    		AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request
			    alipayRequest.setReturnUrl(AlipayUtil.ReturnUrl+"?orderNumber="+out_trade_no);
			    alipayRequest.setNotifyUrl(AlipayUtil.NotifyUrl);//在公共参数中设置回跳和通知地址
			    alipayRequest.setBizContent("{" +
			        "    \"out_trade_no\":\""+out_trade_no+"\"," +  //商户订单号，需要保证不重复
			        "    \"total_amount\":\""+amount+"\"," +	//金额
			        "    \"subject\":\""+subject+"\"," +	//订单标题
			        "    \"seller_id\":\""+AlipayUtil.PID+"\"," +
			        "    \"product_code\":\""+QUICK_WAP_PAY+"\"" +
			        "  }");//填充业务参数
				String form = AlipayUtil.alipayClient.pageExecute(alipayRequest).getBody();
				LogUtil.Info("发起支付获取wap form html成功");
				return form;
			}
	    	 
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * APP支付获取body
	 * @param out_trade_no	订单号
	 * @param amount		金额
	 * @param subject		支付提示信息
	 * @param body			支付内容
	 * @return
	 */
	public static String  AppPayGetBody(String out_trade_no,Double amount,String subject){
		LogUtil.Info("AppPayGetBody amount="+amount+" out_trade_no="+out_trade_no);
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody(subject);
		model.setSubject(subject);
		model.setOutTradeNo(out_trade_no);
		model.setTimeoutExpress("30m");
		model.setTotalAmount(amount.toString());
		model.setProductCode("QUICK_MSECURITY_PAY");
		request.setBizModel(model);
		request.setNotifyUrl(NotifyUrl);
		try {
		        //这里和普通的接口调用不同，使用的是sdkExecute
		        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
		        LogUtil.Info(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。
		        return response.getBody();
		    } catch (AlipayApiException e) {
		        e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 主动查询订单状态
	 * @param out_trade_no
	 * @return
	 */
	public static AliPayQueryResponse queryTrade(String out_trade_no){
		try {
			LogUtil.Info("开始发起订单查询[订单号="+out_trade_no+"]");
			AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//创建API对应的request类
			request.setBizContent("{" +
			"    \"out_trade_no\":\""+out_trade_no+"\""+
			"  }");//设置业务参数
			 AlipayTradeQueryResponse response = alipayClient.execute(request);
			 String body=response.getBody();
			 LogUtil.Info("订单查询返回结果["+body+"]");
			 if (body!=null) {
				 LogUtil.Info("开始JSON对象数据解析");
					AliPayQueryResponse  aliPayQueryResponse=JsonUtil.fromJson(body, AliPayQueryResponse.class);
					if (aliPayQueryResponse!=null) {
						LogUtil.Info("JSON对象数据="+aliPayQueryResponse.toString());
					}else {
						LogUtil.Info("JSON对象数据=NULL");
					}
					 return aliPayQueryResponse;
			 }
			
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			LogUtil.Info("订单查询出现异常"+e);
		}	
		return null;
	}
	
	/**
	 * 退款
	 * @param out_trade_no  订单号(二选一)
	 * @param trade_no      交易号(二选一)
	 * @param refund_amount 需要退款的金额，该金额不能大于订单金额,单位为元，支持两位小数
	 * @param refund_reason 退款的原因说明
	 * @param out_request_no 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
	 */
	public static boolean AliPayRefund(String out_trade_no,String trade_no,String refund_amount,String refund_reason,String out_request_no){
		try {
			AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
			StringBuffer bizString=new StringBuffer("{");
			if (out_trade_no!=null) {
				bizString.append("\"out_trade_no\":\""+out_trade_no+"\",");
			}
			if (trade_no!=null) {
				bizString.append("\"trade_no\":\""+trade_no+"\",");
			}
			if (out_request_no!=null) {
				bizString.append("\"out_request_no\":\""+out_request_no+"\",");
			}
			bizString.append("\"refund_amount\":"+refund_amount+"," +
					"\"refund_reason\":\""+refund_reason+"\"" +
					"}");
			request.setBizContent( bizString.toString());
			
			AlipayTradeRefundResponse response = AlipayUtil.alipayClient.execute(request);
			LogUtil.Info("AlipayTradeRefundResponse ="+JsonUtil.toJson(response));
			if(response.isSuccess()){
				return true;
			} else {
				System.out.println("调用失败");
				LogUtil.Info("调用失败");
			}
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			LogUtil.Info("AlipayApiException ="+e.toString());
		}
		return false;
	}
	
	/**
	 * 退款查询
	 * @param out_trade_no 支付宝交易号，和商户订单号不能同时为空
	 * @param trade_no	订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no如果同时存在优先取trade_no
	 * @param out_request_no  	请求退款接口时，传入的退款请求号，如果在退款请求时未传入，则该值为创建交易时的外部交易号
	 * @return 
	 */
	public static AlipayTradeFastpayRefundQueryResponse AliPayRefundQuery(String out_trade_no,String trade_no,String out_request_no){
		try {
			AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
			StringBuffer bizString=new StringBuffer("{");
			if (out_trade_no!=null) {
				bizString.append("\"out_trade_no\":\""+out_trade_no+"\",");
			}
			if (trade_no!=null) {
				bizString.append("\"trade_no\":\""+trade_no+"\",");
			}
			if (out_request_no!=null) {
				bizString.append("\"out_request_no\":\""+out_request_no+"\"");
			}
			bizString.append("}");
			request.setBizContent(bizString.toString());
			AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
			LogUtil.Info("AlipayTradeFastpayRefundQueryResponse ="+JsonUtil.toJson(response));
			if(response.isSuccess()){
				return response;
			} else {
				System.out.println("调用失败");
			}
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			LogUtil.Info("AlipayApiException ="+e.toString());
		}
		return null;
	}
	
	
	/**
	 * APP支付签名 
	 * @param out_trade_no	订单号
	 * @param amount		金额
	 * @param subject		主题
	 * @return
	 */
	 public static String AliPayGetOrderInfo(String out_trade_no,Double amount,String subject) {
	      String[] parameters={
	            "service=\"mobile.securitypay.pay\"",//固定值（手机快捷支付）
	            "partner=\""+APP_ID+"\"",//合作身份者ID（16位）
	            "_input_charset=\""+CHARSET+"\"",
	            "notify_url=\""+NotifyUrl+"\"",//通知地址
	            "out_trade_no=\""+out_trade_no+"\"",//商户内部订单号
	            "subject=\""+subject+"\"",//测试
	            "payment_type=\"1\"",//固定值
	            "seller_id=\""+PID+"\"",//账户邮箱
	            "total_fee=\""+amount+"\"",//支付金额（元）
	            "body=\"订单说明\"",//订单说明            
	            "it_b_pay=\"30m\""//（订单过期时间 30分钟过期无效）
	      };
	      String orderInfo = signAllString(parameters);
	      return orderInfo;
	   }
	
	 /**
	  * 支付宝签名
	  * @param array
	  * @return
	  */
	 public static String signAllString(String [] array){
	    StringBuffer sb = new StringBuffer("");
	    for (int i = 0; i < array.length; i++) {
	       if(i==(array.length-1)){
	          sb.append(array[i]);
	       }else{
	          sb.append(array[i]+"&");
	       }
	    }
	    System.out.println(sb.toString());
	    String sign = "";
	    try {
	       sign = URLEncoder.encode(RSA.sign(sb.toString(), APP_PRIVATE_KEY, "utf-8"), "utf-8");//private_key私钥
	    } catch (UnsupportedEncodingException e) {
	       e.printStackTrace();
	    }
	    sb.append("&sign=\""+sign+"\"&");
	    sb.append("sign_type=\"RSA\"");
	    return sb.toString();
	 }
	 
	 /**
	  * JAVA服务端验证异步通知信息参数示例
	  * @param request
	  * @return
	  */
	 public boolean checkSignature(HttpServletRequest request){
		//获取支付宝POST过来反馈信息
		 Map<String,String> params = new HashMap<String,String>();
		 Map requestParams = request.getParameterMap();
		 for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
		     String name = (String) iter.next();
		     String[] values = (String[]) requestParams.get(name);
		     String valueStr = "";
		     for (int i = 0; i < values.length; i++) {
		         valueStr = (i == values.length - 1) ? valueStr + values[i]
		                     : valueStr + values[i] + ",";
		   	}
		     //乱码解决，这段代码在出现乱码时使用。
		 	//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
		 	params.put(name, valueStr);
		 }
		 //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
		 //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
		 try {
			 String charset ="utf-8";
			 return AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, charset,"RSA2");
		 } catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		 }
		 return false;
	 }
	 
	 /**
	  * 支付宝单笔转账
	  * @param payee_account  收款方账户(支付宝账户)
	  * @param amount 金额(单位：元)
	  * @param payer 收款方真实姓名
	  * @param memo 备注
	  * @param orderNum 订单号
	  */
	 public static void ailPayTransfer(String payee_account,String amount,String orderNum,String memo) {
		
		 try {
				AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
				AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
				request.setBizContent("{" +
				"out_biz_no:"+orderNum+"," +//商户转账唯一订单号。
				"payee_type:"+PAYEE_TYPE+"," +//收款方账户类型ALIPAY_LOGONID：支付宝登录号，支持邮箱和手机号格式。
				"payee_account:"+payee_account+"," +//收款方账户。与payee_type配合使用。付款方和收款方不能是同一个账户。
				"amount:"+amount+"," +//金额
				"payer_show_name:"+SOURCE+"," + //付款方姓名
//				"payee_real_name:"+payer+"," +//收款方真实姓名
				"remark:"+memo+
				"  }");
				AlipayFundTransToaccountTransferResponse response;
				response = alipayClient.execute(request);
				if(response.isSuccess()){
					System.out.println("调用成功");
					} else {
					System.out.println("调用失败");
					}
			} catch (AlipayApiException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("出错");
			}	
		}
}
